#!/usr/bin/env node

/**
 * Error Handling Compliance Checker
 * Validates that the project follows unified error handling patterns
 */

const fs = require('fs');
const path = require('path');
const { ErrorFactory, ErrorHandler } = require('../lib/utils/errors');

class ErrorHandlingChecker {
  constructor() {
    this.projectRoot = process.cwd();
    this.issues = [];
    this.stats = {
      filesChecked: 0,
      errorsFound: 0,
      warningsFound: 0,
      violationsFixed: 0
    };
  }

  /**
   * Run comprehensive error handling compliance check
   * @returns {Object} Check results
   */
  async checkCompliance() {
    console.log('='.repeat(60));
    console.log('           ERROR HANDLING COMPLIANCE CHECKER');
    console.log('='.repeat(60));
    console.log('');

    // Check for native Error usage
    this.checkNativeErrorUsage();

    // Check for proper error imports
    this.checkErrorImports();

    // Check for error handling patterns
    this.checkErrorHandlingPatterns();

    // Validate error handling in key files
    this.validateKeyFiles();

    // Generate report
    this.generateReport();

    return {
      stats: this.stats,
      issues: this.issues,
      compliant: this.stats.errorsFound === 0
    };
  }

  /**
   * Check for native Error usage that should be replaced
   */
  checkNativeErrorUsage() {
    console.log('🔍 Checking for native Error usage...');

    const jsFiles = this.findJavaScriptFiles();
    const nativeErrorPattern = /throw new Error\s*\(/g;

    jsFiles.forEach(filePath => {
      try {
        const content = fs.readFileSync(filePath, 'utf8');
        const matches = content.match(nativeErrorPattern);

        if (matches) {
          this.stats.errorsFound += matches.length;
          this.issues.push({
            type: 'error',
            file: filePath,
            message: `Found ${matches.length} native Error usage(s)`,
            suggestion: 'Replace with ErrorFactory methods'
          });
        }
        this.stats.filesChecked++;
      } catch (error) {
        console.warn(`Could not read file ${filePath}: ${error.message}`);
      }
    });
  }

  /**
   * Check for proper error handling imports
   */
  checkErrorImports() {
    console.log('📦 Checking error handling imports...');

    const jsFiles = this.findJavaScriptFiles();
    const errorImportPattern = /require\s*\(\s*['"].*\/utils\/errors['"]\s*\)/g;

    let filesWithErrors = jsFiles.filter(filePath => {
      try {
        const content = fs.readFileSync(filePath, 'utf8');
        const hasThrowOrError = /throw\s+|\.catch\s*\(/.test(content);
        const hasErrorImport = errorImportPattern.test(content);

        return hasThrowOrError && !hasErrorImport;
      } catch (error) {
        return false;
      }
    });

    if (filesWithErrors.length > 0) {
      this.stats.errorsFound += filesWithErrors.length;
      this.issues.push({
        type: 'error',
        files: filesWithErrors,
        message: `Found ${filesWithErrors.length} files using errors without proper imports`,
        suggestion: 'Add error handling imports: const { ErrorFactory, ErrorHandler } = require("../utils/errors")'
      });
    }
  }

  /**
   * Check for proper error handling patterns
   */
  checkErrorHandlingPatterns() {
    console.log('🔧 Checking error handling patterns...');

    const jsFiles = this.findJavaScriptFiles();

    // Check for missing catch blocks
    const tryPattern = /try\s*\{/g;
    const catchPattern = /catch\s*\(/g;

    jsFiles.forEach(filePath => {
      try {
        const content = fs.readFileSync(filePath, 'utf8');
        const tries = (content.match(tryPattern) || []).length;
        const catches = (content.match(catchPattern) || []).length;

        if (tries > catches) {
          this.stats.errorsFound += (tries - catches);
          this.issues.push({
            type: 'error',
            file: filePath,
            message: `Missing ${tries - catches} catch blocks for try statements`,
            suggestion: 'Add proper catch blocks with error handling'
          });
        }

        // Check for empty catch blocks
        const emptyCatchPattern = /catch\s*\([^)]*\)\s*\{\s*\}/g;
        const emptyCatches = content.match(emptyCatchPattern);

        if (emptyCatches) {
          this.stats.warningsFound += emptyCatches.length;
          this.issues.push({
            type: 'warning',
            file: filePath,
            message: `Found ${emptyCatches.length} empty catch blocks`,
            suggestion: 'Add proper error handling in catch blocks'
          });
        }
      } catch (error) {
        console.warn(`Could not analyze file ${filePath}: ${error.message}`);
      }
    });
  }

  /**
   * Validate error handling in key files
   */
  validateKeyFiles() {
    console.log('🎯 Validating key files...');

    const keyFiles = [
      'lib/mcp/server.js',
      'lib/http/server.js',
      'lib/config/config-manager.js',
      'lib/integration/service-manager.js',
      'index.js'
    ];

    keyFiles.forEach(relativePath => {
      const filePath = path.join(this.projectRoot, relativePath);

      if (fs.existsSync(filePath)) {
        this.validateFileErrorHandling(filePath, relativePath);
      } else {
        this.issues.push({
          type: 'warning',
          file: relativePath,
          message: 'Key file not found',
          suggestion: 'Ensure all key files are present'
        });
      }
    });
  }

  /**
   * Validate error handling in a specific file
   * @param {string} filePath - File path
   * @param {string} relativePath - Relative path for reporting
   */
  validateFileErrorHandling(filePath, relativePath) {
    try {
      const content = fs.readFileSync(filePath, 'utf8');

      // Check for proper error imports
      const hasErrorImport = /require\s*\(\s*['"].*\/utils\/errors['"]\s*\)/.test(content);
      const hasErrorHandling = /throw\s+|\.catch\s*\(|ErrorFactory|ErrorHandler/.test(content);

      if (hasErrorHandling && !hasErrorImport) {
        this.stats.errorsFound++;
        this.issues.push({
          type: 'error',
          file: relativePath,
          message: 'Key file uses error handling without proper imports',
          suggestion: 'Add error handling imports'
        });
      }

      // Check for ErrorFactory usage
      const errorFactoryUsage = (content.match(/ErrorFactory\./g) || []).length;
      const nativeErrorUsage = (content.match(/throw new Error\s*\(/g) || []).length;

      if (nativeErrorUsage > 0 && errorFactoryUsage === 0) {
        this.stats.errorsFound += nativeErrorUsage;
        this.issues.push({
          type: 'error',
          file: relativePath,
          message: `Key file uses ${nativeErrorUsage} native Error(s) without ErrorFactory`,
          suggestion: 'Replace with ErrorFactory methods'
        });
      }

    } catch (error) {
      this.issues.push({
        type: 'error',
        file: relativePath,
        message: `Could not validate file: ${error.message}`,
        suggestion: 'Check file accessibility and permissions'
      });
    }
  }

  /**
   * Find all JavaScript files in the project
   * @returns {Array} Array of file paths
   */
  findJavaScriptFiles() {
    const jsFiles = [];
    const excludeDirs = ['node_modules', '.git', 'coverage', 'dist', 'build'];

    const findFiles = (dir) => {
      if (!fs.existsSync(dir)) return [];

      const foundFiles = [];

      try {
        const items = fs.readdirSync(dir, { withFileTypes: true });

        for (const item of items) {
          const fullPath = path.join(dir, item.name);

          if (item.isDirectory() && !excludeDirs.includes(item.name)) {
            // Recursively search subdirectories
            foundFiles.push(...findFiles(fullPath));
          } else if (item.isFile() && item.name.endsWith('.js')) {
            foundFiles.push(fullPath);
          }
        }
      } catch (error) {
        // Skip directories that can't be read
        console.warn(`Warning: Could not read directory ${dir}: ${error.message}`);
      }

      return foundFiles;
    };

    jsFiles.push(...findFiles(this.projectRoot));
    return jsFiles;
  }

  /**
   * Generate and display compliance report
   */
  generateReport() {
    console.log('');
    console.log('📊 COMPLIANCE REPORT');
    console.log('─'.repeat(60));
    console.log(`Files checked: ${this.stats.filesChecked}`);
    console.log(`Errors found: ${this.stats.errorsFound}`);
    console.log(`Warnings found: ${this.stats.warningsFound}`);
    console.log('');

    if (this.issues.length === 0) {
      console.log('✅ All checks passed! Error handling is fully compliant.');
      console.log('');
      console.log('🎉 Great job following unified error handling patterns!');
    } else {
      console.log('❌ Issues found that need attention:');
      console.log('');

      const errors = this.issues.filter(issue => issue.type === 'error');
      const warnings = this.issues.filter(issue => issue.type === 'warning');

      if (errors.length > 0) {
        console.log('🚨 ERRORS:');
        errors.forEach((issue, index) => {
          console.log(`  ${index + 1}. ${issue.file || 'Multiple files'}`);
          console.log(`     ${issue.message}`);
          console.log(`     💡 ${issue.suggestion}`);
          console.log('');
        });
      }

      if (warnings.length > 0) {
        console.log('⚠️  WARNINGS:');
        warnings.forEach((issue, index) => {
          console.log(`  ${index + 1}. ${issue.file || 'Multiple files'}`);
          console.log(`     ${issue.message}`);
          console.log(`     💡 ${issue.suggestion}`);
          console.log('');
        });
      }

      console.log('Please fix these issues to ensure proper error handling compliance.');
    }

    console.log('─'.repeat(60));
    console.log('');
  }

  /**
   * Fix common error handling issues automatically
   * @returns {Object} Fix results
   */
  async autoFixIssues() {
    console.log('🔧 Attempting to auto-fix issues...');

    let fixesApplied = 0;

    // This could be extended to automatically fix common issues
    // For now, just report what would be fixed

    for (const issue of this.issues) {
      if (issue.type === 'error' && issue.suggestion.includes('ErrorFactory')) {
        console.log(`📝 Would fix: ${issue.file} - ${issue.message}`);
        fixesApplied++;
      }
    }

    console.log(`📝 ${fixesApplied} issues could be automatically fixed.`);
    console.log('💡 Manual review and fixing is recommended for best results.');

    return { fixesApplied, issues: this.issues };
  }
}

/**
 * Main execution function
 */
async function main() {
  const checker = new ErrorHandlingChecker();

  // Parse command line arguments
  const args = process.argv.slice(2);
  const shouldAutoFix = args.includes('--fix') || args.includes('-f');

  try {
    const results = await checker.checkCompliance();

    if (shouldAutoFix && !results.compliant) {
      console.log('');
      await checker.autoFixIssues();
    }

    // Exit with appropriate code
    process.exit(results.compliant ? 0 : 1);

  } catch (error) {
    console.error('💥 Error during compliance check:', error.message);
    process.exit(1);
  }
}

// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
  console.error('💥 Uncaught exception:', error.message);
  process.exit(1);
});

// Handle interrupt signals
process.on('SIGINT', () => {
  console.log('\n🛑 Error handling check interrupted by user');
  process.exit(130);
});

// Run main function
if (require.main === module) {
  main();
}

module.exports = { ErrorHandlingChecker, main };